// 简单的定义一个接口
/**
 * @param labeledObj
 * 类型检查器会查看 printLabel 的调用。 printLabel 有一个参数，并要求这个
 * 对象参数有一个名为 label 类型为 string 的属性。 需要注意的是，我们传入的
 * 对象参数实际上会包含很多属性，但是编译器只会检查那些必需的属性是否存在，
 * 并且其类型是否匹配。
 */

// function printLabel(labeledObj: { label: string }) {
//   console.log(labeledObj.label)
// }
// let myObj = { size: 10, label: '这是一段字符串' }
// printLabel(myObj) //这是一段字符串

// 将函数数据类型转成一个接口
/**
 * LabeledValue 接口就好比一个名字，用来描述上面例子里的要求。 它代表了有
 * 一个 label 属性且类型为 string 的对象。 需要注意的是，我们在这里并不能像
 * 在其它语言里一样，说传给 printLabel 的对象实现了这个接口。我们只会去关
 * 注值的外形。 只要传入的对象满足上面提到的必要条件，那么它就是被允许的。
 *
 * 还有一点值得提的是，类型检查器不会去检查属性的顺序，只要相应的属性存在并
 * 且类型也是对的就可以。
 *
 * 可选参数
 * 定义不必填写的值,能做简单的字段检查 ,比如我拼写错了sizes
 * 
 * 只读属性
 * 一些对象属性只能在对象刚刚创建的时候修改其值。 你可以在属性名前用 readonly 来指定只读属性
 * 
 */

interface LabeledValue {
  label: string
  size?: number
  readonly readValue?: string
}
function printLabel2(labeledObj: LabeledValue) {
  console.log(labeledObj.label, labeledObj.size, labeledObj.readValue)
}
let myObj2 = { size: 10, label: '这是一段字符串', readValue: '只读参数' }
// printLabel2(myObj2) //这是一段字符串


// 额外的属性检查:
// ?

// 函数类型
interface SearchFunc {
  (source: string, subString: string): boolean; // 定义一个函数接口,规定传参和返回值得类型的类型
}
let mySearch: SearchFunc = (source: string, subString: string) => {
  let result = source.search(subString);
  return result > -1;
}
// mySearch("22", 2) //error
mySearch("22", "2")